agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v21 5/8] Row pattern recognition patch (executor). 153+ messages / 2 participants [nested] [flat]
* [PATCH v21 5/8] Row pattern recognition patch (executor). @ 2024-08-26 04:32 Tatsuo Ishii <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Tatsuo Ishii @ 2024-08-26 04:32 UTC (permalink / raw) --- src/backend/executor/nodeWindowAgg.c | 1610 +++++++++++++++++++++++++- src/backend/utils/adt/windowfuncs.c | 37 +- src/include/catalog/pg_proc.dat | 6 + src/include/nodes/execnodes.h | 30 + 4 files changed, 1671 insertions(+), 12 deletions(-) diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 3221fa1522..140bb3941e 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -36,6 +36,7 @@ #include "access/htup_details.h" #include "catalog/objectaccess.h" #include "catalog/pg_aggregate.h" +#include "catalog/pg_collation_d.h" #include "catalog/pg_proc.h" #include "executor/executor.h" #include "executor/nodeWindowAgg.h" @@ -48,6 +49,7 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/datum.h" +#include "utils/fmgroids.h" #include "utils/expandeddatum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" @@ -159,6 +161,43 @@ typedef struct WindowStatePerAggData bool restart; /* need to restart this agg in this cycle? */ } WindowStatePerAggData; +/* + * Set of StringInfo. Used in RPR. + */ +typedef struct StringSet +{ + StringInfo *str_set; + Size set_size; /* current array allocation size in number of + * items */ + int set_index; /* current used size */ +} StringSet; + +/* + * Allowed subsequent PATTERN variables positions. + * Used in RPR. + * + * pos represents the pattern variable defined order in DEFINE caluase. For + * example. "DEFINE START..., UP..., DOWN ..." and "PATTERN START UP DOWN UP" + * will create: + * VariablePos[0].pos[0] = 0; START + * VariablePos[1].pos[0] = 1; UP + * VariablePos[1].pos[1] = 3; UP + * VariablePos[2].pos[0] = 2; DOWN + * + * Note that UP has two pos because UP appears in PATTERN twice. + * + * By using this strucrture, we can know which pattern variable can be followed + * by which pattern variable(s). For example, START can be followed by UP and + * DOWN since START's pos is 0, and UP's pos is 1 or 3, DOWN's pos is 2. + * DOWN can be followed by UP since UP's pos is either 1 or 3. + * + */ +#define NUM_ALPHABETS 26 /* we allow [a-z] variable initials */ +typedef struct VariablePos +{ + int pos[NUM_ALPHABETS]; /* postion(s) in PATTERN */ +} VariablePos; + static void initialize_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate); @@ -184,6 +223,7 @@ static void release_partition(WindowAggState *winstate); static int row_is_in_frame(WindowAggState *winstate, int64 pos, TupleTableSlot *slot); + static void update_frameheadpos(WindowAggState *winstate); static void update_frametailpos(WindowAggState *winstate); static void update_grouptailpos(WindowAggState *winstate); @@ -195,9 +235,48 @@ static Datum GetAggInitVal(Datum textInitVal, Oid transtype); static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2); + +static int WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot, + int relpos, int seektype, bool set_mark, + bool *isnull, bool *isout); static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot); +static void attno_map(Node *node); +static bool attno_map_walker(Node *node, void *context); +static int row_is_in_reduced_frame(WindowObject winobj, int64 pos); +static bool rpr_is_defined(WindowAggState *winstate); + +static void create_reduced_frame_map(WindowAggState *winstate); +static int get_reduced_frame_map(WindowAggState *winstate, int64 pos); +static void register_reduced_frame_map(WindowAggState *winstate, int64 pos, + int val); +static void clear_reduced_frame_map(WindowAggState *winstate); +static void update_reduced_frame(WindowObject winobj, int64 pos); + +static int64 evaluate_pattern(WindowObject winobj, int64 current_pos, + char *vname, StringInfo encoded_str, bool *result); + +static bool get_slots(WindowObject winobj, int64 current_pos); + +static int search_str_set(char *pattern, StringSet * str_set, + VariablePos * variable_pos); +static char pattern_initial(WindowAggState *winstate, char *vname); +static int do_pattern_match(char *pattern, char *encoded_str); + +static StringSet * string_set_init(void); +static void string_set_add(StringSet * string_set, StringInfo str); +static StringInfo string_set_get(StringSet * string_set, int index); +static int string_set_get_size(StringSet * string_set); +static void string_set_discard(StringSet * string_set); +static VariablePos * variable_pos_init(void); +static void variable_pos_register(VariablePos * variable_pos, char initial, + int pos); +static bool variable_pos_compare(VariablePos * variable_pos, + char initial1, char initial2); +static int variable_pos_fetch(VariablePos * variable_pos, char initial, + int index); +static void variable_pos_discard(VariablePos * variable_pos); /* * initialize_windowaggregate @@ -774,10 +853,12 @@ eval_windowaggregates(WindowAggState *winstate) * transition function, or * - we have an EXCLUSION clause, or * - if the new frame doesn't overlap the old one + * - if RPR is enabled * * Note that we don't strictly need to restart in the last case, but if * we're going to remove all rows from the aggregation anyway, a restart * surely is faster. + * we restart aggregation too. *---------- */ numaggs_restart = 0; @@ -788,7 +869,8 @@ eval_windowaggregates(WindowAggState *winstate) (winstate->aggregatedbase != winstate->frameheadpos && !OidIsValid(peraggstate->invtransfn_oid)) || (winstate->frameOptions & FRAMEOPTION_EXCLUSION) || - winstate->aggregatedupto <= winstate->frameheadpos) + winstate->aggregatedupto <= winstate->frameheadpos || + rpr_is_defined(winstate)) { peraggstate->restart = true; numaggs_restart++; @@ -862,7 +944,22 @@ eval_windowaggregates(WindowAggState *winstate) * head, so that tuplestore can discard unnecessary rows. */ if (agg_winobj->markptr >= 0) - WinSetMarkPosition(agg_winobj, winstate->frameheadpos); + { + int64 markpos = winstate->frameheadpos; + + if (rpr_is_defined(winstate)) + { + /* + * If RPR is used, it is possible PREV wants to look at the + * previous row. So the mark pos should be frameheadpos - 1 + * unless it is below 0. + */ + markpos -= 1; + if (markpos < 0) + markpos = 0; + } + WinSetMarkPosition(agg_winobj, markpos); + } /* * Now restart the aggregates that require it. @@ -917,6 +1014,14 @@ eval_windowaggregates(WindowAggState *winstate) { winstate->aggregatedupto = winstate->frameheadpos; ExecClearTuple(agg_row_slot); + + /* + * If RPR is defined, we do not use aggregatedupto_nonrestarted. To + * avoid assertion failure below, we reset aggregatedupto_nonrestarted + * to frameheadpos. + */ + if (rpr_is_defined(winstate)) + aggregatedupto_nonrestarted = winstate->frameheadpos; } /* @@ -930,6 +1035,12 @@ eval_windowaggregates(WindowAggState *winstate) { int ret; +#ifdef RPR_DEBUG + elog(DEBUG1, "===== loop in frame starts: aggregatedupto: " INT64_FORMAT " aggregatedbase: " INT64_FORMAT, + winstate->aggregatedupto, + winstate->aggregatedbase); +#endif + /* Fetch next row if we didn't already */ if (TupIsNull(agg_row_slot)) { @@ -945,9 +1056,52 @@ eval_windowaggregates(WindowAggState *winstate) ret = row_is_in_frame(winstate, winstate->aggregatedupto, agg_row_slot); if (ret < 0) break; + if (ret == 0) goto next_tuple; + if (rpr_is_defined(winstate)) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "reduced_frame_map: %d aggregatedupto: " INT64_FORMAT " aggregatedbase: " INT64_FORMAT, + get_reduced_frame_map(winstate, + winstate->aggregatedupto), + winstate->aggregatedupto, + winstate->aggregatedbase); +#endif + /* + * If the row status at currentpos is already decided and current + * row status is not decided yet, it means we passed the last + * reduced frame. Time to break the loop. + */ + if (get_reduced_frame_map(winstate, + winstate->currentpos) != RF_NOT_DETERMINED && + get_reduced_frame_map(winstate, + winstate->aggregatedupto) == RF_NOT_DETERMINED) + break; + + /* + * Otherwise we need to calculate the reduced frame. + */ + ret = row_is_in_reduced_frame(winstate->agg_winobj, + winstate->aggregatedupto); + if (ret == -1) /* unmatched row */ + break; + + /* + * Check if current row needs to be skipped due to no match. + */ + if (get_reduced_frame_map(winstate, + winstate->aggregatedupto) == RF_SKIPPED && + winstate->aggregatedupto == winstate->aggregatedbase) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "skip current row for aggregation"); +#endif + break; + } + } + /* Set tuple context for evaluation of aggregate arguments */ winstate->tmpcontext->ecxt_outertuple = agg_row_slot; @@ -976,6 +1130,7 @@ next_tuple: ExecClearTuple(agg_row_slot); } + /* The frame's end is not supposed to move backwards, ever */ Assert(aggregatedupto_nonrestarted <= winstate->aggregatedupto); @@ -995,7 +1150,6 @@ next_tuple: &winstate->perfunc[wfuncno], peraggstate, result, isnull); - /* * save the result in case next row shares the same frame. * @@ -1090,6 +1244,7 @@ begin_partition(WindowAggState *winstate) winstate->framehead_valid = false; winstate->frametail_valid = false; winstate->grouptail_valid = false; + create_reduced_frame_map(winstate); winstate->spooled_rows = 0; winstate->currentpos = 0; winstate->frameheadpos = 0; @@ -2053,6 +2208,11 @@ ExecWindowAgg(PlanState *pstate) CHECK_FOR_INTERRUPTS(); +#ifdef RPR_DEBUG + elog(DEBUG1, "ExecWindowAgg called. pos: " INT64_FORMAT, + winstate->currentpos); +#endif + if (winstate->status == WINDOWAGG_DONE) return NULL; @@ -2221,6 +2381,17 @@ ExecWindowAgg(PlanState *pstate) /* don't evaluate the window functions when we're in pass-through mode */ if (winstate->status == WINDOWAGG_RUN) { + /* + * If RPR is defined and skip mode is next row, we need to clear + * existing reduced frame info so that we newly calculate the info + * starting from current row. + */ + if (rpr_is_defined(winstate)) + { + if (winstate->rpSkipTo == ST_NEXT_ROW) + clear_reduced_frame_map(winstate); + } + /* * Evaluate true window functions */ @@ -2388,6 +2559,9 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) TupleDesc scanDesc; ListCell *l; + TargetEntry *te; + Expr *expr; + /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); @@ -2486,6 +2660,16 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc, &TTSOpsMinimalTuple); + winstate->prev_slot = ExecInitExtraTupleSlot(estate, scanDesc, + &TTSOpsMinimalTuple); + + winstate->next_slot = ExecInitExtraTupleSlot(estate, scanDesc, + &TTSOpsMinimalTuple); + + winstate->null_slot = ExecInitExtraTupleSlot(estate, scanDesc, + &TTSOpsMinimalTuple); + winstate->null_slot = ExecStoreAllNullTuple(winstate->null_slot); + /* * create frame head and tail slots only if needed (must create slots in * exactly the same cases that update_frameheadpos and update_frametailpos @@ -2667,6 +2851,43 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) winstate->inRangeAsc = node->inRangeAsc; winstate->inRangeNullsFirst = node->inRangeNullsFirst; + /* Set up SKIP TO type */ + winstate->rpSkipTo = node->rpSkipTo; + /* Set up row pattern recognition PATTERN clause */ + winstate->patternVariableList = node->patternVariable; + winstate->patternRegexpList = node->patternRegexp; + + /* Set up row pattern recognition DEFINE clause */ + winstate->defineInitial = node->defineInitial; + winstate->defineVariableList = NIL; + winstate->defineClauseList = NIL; + if (node->defineClause != NIL) + { + /* + * Tweak arg var of PREV/NEXT so that it refers to scan/inner slot. + */ + foreach(l, node->defineClause) + { + char *name; + ExprState *exps; + + te = lfirst(l); + name = te->resname; + expr = te->expr; + +#ifdef RPR_DEBUG + elog(DEBUG1, "defineVariable name: %s", name); +#endif + winstate->defineVariableList = + lappend(winstate->defineVariableList, + makeString(pstrdup(name))); + attno_map((Node *) expr); + exps = ExecInitExpr(expr, (PlanState *) winstate); + winstate->defineClauseList = + lappend(winstate->defineClauseList, exps); + } + } + winstate->all_first = true; winstate->partition_spooled = false; winstate->more_partitions = false; @@ -2674,6 +2895,64 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) return winstate; } +/* + * Rewrite varno of Var node that is the argument of PREV/NET so that it sees + * scan tuple (PREV) or inner tuple (NEXT). + */ +static void +attno_map(Node *node) +{ + (void) expression_tree_walker(node, attno_map_walker, NULL); +} + +static bool +attno_map_walker(Node *node, void *context) +{ + FuncExpr *func; + int nargs; + Expr *expr; + Var *var; + + if (node == NULL) + return false; + + if (IsA(node, FuncExpr)) + { + func = (FuncExpr *) node; + + if (func->funcid == F_PREV || func->funcid == F_NEXT) + { + /* sanity check */ + nargs = list_length(func->args); + if (list_length(func->args) != 1) + elog(ERROR, "PREV/NEXT must have 1 argument but function %d has %d args", + func->funcid, nargs); + + expr = (Expr *) lfirst(list_head(func->args)); + if (!IsA(expr, Var)) + elog(ERROR, "PREV/NEXT's arg is not Var"); /* XXX: is it possible + * that arg type is + * Const? */ + var = (Var *) expr; + + if (func->funcid == F_PREV) + + /* + * Rewrite varno from OUTER_VAR to regular var no so that the + * var references scan tuple. + */ + var->varno = var->varnosyn; + else + var->varno = INNER_VAR; + +#ifdef RPR_DEBUG + elog(DEBUG1, "PREV/NEXT's varno is rewritten to: %d", var->varno); +#endif + } + } + return expression_tree_walker(node, attno_map_walker, NULL); +} + /* ----------------- * ExecEndWindowAgg * ----------------- @@ -2723,6 +3002,8 @@ ExecReScanWindowAgg(WindowAggState *node) ExecClearTuple(node->agg_row_slot); ExecClearTuple(node->temp_slot_1); ExecClearTuple(node->temp_slot_2); + ExecClearTuple(node->prev_slot); + ExecClearTuple(node->next_slot); if (node->framehead_slot) ExecClearTuple(node->framehead_slot); if (node->frametail_slot) @@ -3083,7 +3364,8 @@ window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot) return false; if (pos < winobj->markpos) - elog(ERROR, "cannot fetch row before WindowObject's mark position"); + elog(ERROR, "cannot fetch row: " INT64_FORMAT " before WindowObject's mark position: " INT64_FORMAT, + pos, winobj->markpos); oldcontext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_query_memory); @@ -3403,14 +3685,54 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno, WindowAggState *winstate; ExprContext *econtext; TupleTableSlot *slot; - int64 abs_pos; - int64 mark_pos; Assert(WindowObjectIsValid(winobj)); winstate = winobj->winstate; econtext = winstate->ss.ps.ps_ExprContext; slot = winstate->temp_slot_1; + if (WinGetSlotInFrame(winobj, slot, + relpos, seektype, set_mark, + isnull, isout) == 0) + { + econtext->ecxt_outertuple = slot; + return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), + econtext, isnull); + } + + if (isout) + *isout = true; + *isnull = true; + return (Datum) 0; +} + +/* + * WinGetSlotInFrame + * slot: TupleTableSlot to store the result + * relpos: signed rowcount offset from the seek position + * seektype: WINDOW_SEEK_HEAD or WINDOW_SEEK_TAIL + * set_mark: If the row is found/in frame and set_mark is true, the mark is + * moved to the row as a side-effect. + * isnull: output argument, receives isnull status of result + * isout: output argument, set to indicate whether target row position + * is out of frame (can pass NULL if caller doesn't care about this) + * + * Returns 0 if we successfullt got the slot. false if out of frame. + * (also isout is set) + */ +static int +WinGetSlotInFrame(WindowObject winobj, TupleTableSlot *slot, + int relpos, int seektype, bool set_mark, + bool *isnull, bool *isout) +{ + WindowAggState *winstate; + int64 abs_pos; + int64 mark_pos; + int num_reduced_frame; + + Assert(WindowObjectIsValid(winobj)); + winstate = winobj->winstate; + switch (seektype) { case WINDOW_SEEK_CURRENT: @@ -3477,11 +3799,25 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno, winstate->frameOptions); break; } + num_reduced_frame = row_is_in_reduced_frame(winobj, + winstate->frameheadpos); + if (num_reduced_frame < 0) + goto out_of_frame; + else if (num_reduced_frame > 0) + if (relpos >= num_reduced_frame) + goto out_of_frame; break; case WINDOW_SEEK_TAIL: /* rejecting relpos > 0 is easy and simplifies code below */ if (relpos > 0) goto out_of_frame; + + /* + * RPR cares about frame head pos. Need to call + * update_frameheadpos + */ + update_frameheadpos(winstate); + update_frametailpos(winstate); abs_pos = winstate->frametailpos - 1 + relpos; @@ -3548,6 +3884,14 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno, mark_pos = 0; /* keep compiler quiet */ break; } + + num_reduced_frame = row_is_in_reduced_frame(winobj, + winstate->frameheadpos + relpos); + if (num_reduced_frame < 0) + goto out_of_frame; + else if (num_reduced_frame > 0) + abs_pos = winstate->frameheadpos + relpos + + num_reduced_frame - 1; break; default: elog(ERROR, "unrecognized window seek type: %d", seektype); @@ -3566,15 +3910,13 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno, *isout = false; if (set_mark) WinSetMarkPosition(winobj, mark_pos); - econtext->ecxt_outertuple = slot; - return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), - econtext, isnull); + return 0; out_of_frame: if (isout) *isout = true; *isnull = true; - return (Datum) 0; + return -1; } /* @@ -3605,3 +3947,1251 @@ WinGetFuncArgCurrent(WindowObject winobj, int argno, bool *isnull) return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno), econtext, isnull); } + +/* + * rpr_is_defined + * return true if Row pattern recognition is defined. + */ +static +bool +rpr_is_defined(WindowAggState *winstate) +{ + return winstate->patternVariableList != NIL; +} + +/* + * ----------------- + * row_is_in_reduced_frame + * Determine whether a row is in the current row's reduced window frame + * according to row pattern matching + * + * The row must has been already determined that it is in a full window frame + * and fetched it into slot. + * + * Returns: + * = 0, RPR is not defined. + * >0, if the row is the first in the reduced frame. Return the number of rows + * in the reduced frame. + * -1, if the row is unmatched row + * -2, if the row is in the reduced frame but needed to be skipped because of + * AFTER MATCH SKIP PAST LAST ROW + * ----------------- + */ +static +int +row_is_in_reduced_frame(WindowObject winobj, int64 pos) +{ + WindowAggState *winstate = winobj->winstate; + int state; + int rtn; + + if (!rpr_is_defined(winstate)) + { + /* + * RPR is not defined. Assume that we are always in the the reduced + * window frame. + */ + rtn = 0; +#ifdef RPR_DEBUG + elog(DEBUG1, "row_is_in_reduced_frame returns %d: pos: " INT64_FORMAT, + rtn, pos); +#endif + return rtn; + } + + state = get_reduced_frame_map(winstate, pos); + + if (state == RF_NOT_DETERMINED) + { + update_frameheadpos(winstate); + update_reduced_frame(winobj, pos); + } + + state = get_reduced_frame_map(winstate, pos); + + switch (state) + { + int64 i; + int num_reduced_rows; + + case RF_FRAME_HEAD: + num_reduced_rows = 1; + for (i = pos + 1; + get_reduced_frame_map(winstate, i) == RF_SKIPPED; i++) + num_reduced_rows++; + rtn = num_reduced_rows; + break; + + case RF_SKIPPED: + rtn = -2; + break; + + case RF_UNMATCHED: + rtn = -1; + break; + + default: + elog(ERROR, "Unrecognized state: %d at: " INT64_FORMAT, + state, pos); + break; + } + +#ifdef RPR_DEBUG + elog(DEBUG1, "row_is_in_reduced_frame returns %d: pos: " INT64_FORMAT, + rtn, pos); +#endif + return rtn; +} + +#define REDUCED_FRAME_MAP_INIT_SIZE 1024L + +/* + * create_reduced_frame_map + * Create reduced frame map + */ +static +void +create_reduced_frame_map(WindowAggState *winstate) +{ + winstate->reduced_frame_map = + MemoryContextAlloc(winstate->partcontext, + REDUCED_FRAME_MAP_INIT_SIZE); + winstate->alloc_sz = REDUCED_FRAME_MAP_INIT_SIZE; + clear_reduced_frame_map(winstate); +} + +/* + * clear_reduced_frame_map + * Clear reduced frame map + */ +static +void +clear_reduced_frame_map(WindowAggState *winstate) +{ + Assert(winstate->reduced_frame_map != NULL); + MemSet(winstate->reduced_frame_map, RF_NOT_DETERMINED, + winstate->alloc_sz); +} + +/* + * get_reduced_frame_map + * Get reduced frame map specified by pos + */ +static +int +get_reduced_frame_map(WindowAggState *winstate, int64 pos) +{ + Assert(winstate->reduced_frame_map != NULL); + + if (pos < 0 || pos >= winstate->alloc_sz) + elog(ERROR, "wrong pos: " INT64_FORMAT, pos); + + return winstate->reduced_frame_map[pos]; +} + +/* + * register_reduced_frame_map + * Add/replace reduced frame map member at pos. + * If there's no enough space, expand the map. + */ +static +void +register_reduced_frame_map(WindowAggState *winstate, int64 pos, int val) +{ + int64 realloc_sz; + + Assert(winstate->reduced_frame_map != NULL); + + if (pos < 0) + elog(ERROR, "wrong pos: " INT64_FORMAT, pos); + + if (pos > winstate->alloc_sz - 1) + { + realloc_sz = winstate->alloc_sz * 2; + + winstate->reduced_frame_map = + repalloc(winstate->reduced_frame_map, realloc_sz); + + MemSet(winstate->reduced_frame_map + winstate->alloc_sz, + RF_NOT_DETERMINED, realloc_sz - winstate->alloc_sz); + + winstate->alloc_sz = realloc_sz; + } + + winstate->reduced_frame_map[pos] = val; +} + +/* + * update_reduced_frame + * Update reduced frame info. + */ +static +void +update_reduced_frame(WindowObject winobj, int64 pos) +{ + WindowAggState *winstate = winobj->winstate; + ListCell *lc1, + *lc2; + bool expression_result; + int num_matched_rows; + int64 original_pos; + bool anymatch; + StringInfo encoded_str; + StringInfo pattern_str = makeStringInfo(); + StringSet *str_set; + int initial_index; + VariablePos *variable_pos; + bool greedy = false; + int64 result_pos, + i; + + /* + * Set of pattern variables evaluated to true. Each character corresponds + * to pattern variable. Example: str_set[0] = "AB"; str_set[1] = "AC"; In + * this case at row 0 A and B are true, and A and C are true in row 1. + */ + + /* initialize pattern variables set */ + str_set = string_set_init(); + + /* save original pos */ + original_pos = pos; + + /* + * Check if the pattern does not include any greedy quantifier. If it does + * not, we can just apply the pattern to each row. If it succeeds, we are + * done. + */ + foreach(lc1, winstate->patternRegexpList) + { + char *quantifier = strVal(lfirst(lc1)); + + if (*quantifier == '+' || *quantifier == '*') + { + greedy = true; + break; + } + } + + /* + * Non greedy case + */ + if (!greedy) + { + num_matched_rows = 0; + + foreach(lc1, winstate->patternVariableList) + { + char *vname = strVal(lfirst(lc1)); + + encoded_str = makeStringInfo(); + +#ifdef RPR_DEBUG + elog(DEBUG1, "pos: " INT64_FORMAT " pattern vname: %s", + pos, vname); +#endif + expression_result = false; + + /* evaluate row pattern against current row */ + result_pos = evaluate_pattern(winobj, pos, vname, + encoded_str, &expression_result); + if (!expression_result || result_pos < 0) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "expression result is false or out of frame"); +#endif + register_reduced_frame_map(winstate, original_pos, + RF_UNMATCHED); + return; + } + /* move to next row */ + pos++; + num_matched_rows++; + } +#ifdef RPR_DEBUG + elog(DEBUG1, "pattern matched"); +#endif + register_reduced_frame_map(winstate, original_pos, RF_FRAME_HEAD); + + for (i = original_pos + 1; i < original_pos + num_matched_rows; i++) + { + register_reduced_frame_map(winstate, i, RF_SKIPPED); + } + return; + } + + /* + * Greedy quantifiers included. Loop over until none of pattern matches or + * encounters end of frame. + */ + for (;;) + { + result_pos = -1; + + /* + * Loop over each PATTERN variable. + */ + anymatch = false; + encoded_str = makeStringInfo(); + + forboth(lc1, winstate->patternVariableList, lc2, + winstate->patternRegexpList) + { + char *vname = strVal(lfirst(lc1)); +#ifdef RPR_DEBUG + char *quantifier = strVal(lfirst(lc2)); + + elog(DEBUG1, "pos: " INT64_FORMAT " pattern vname: %s quantifier: %s", + pos, vname, quantifier); +#endif + expression_result = false; + + /* evaluate row pattern against current row */ + result_pos = evaluate_pattern(winobj, pos, vname, + encoded_str, &expression_result); + if (expression_result) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "expression result is true"); +#endif + anymatch = true; + } + + /* + * If out of frame, we are done. + */ + if (result_pos < 0) + break; + } + + if (!anymatch) + { + /* none of patterns matched. */ + break; + } + + string_set_add(str_set, encoded_str); + +#ifdef RPR_DEBUG + elog(DEBUG1, "pos: " INT64_FORMAT " encoded_str: %s", + encoded_str->data); +#endif + + /* move to next row */ + pos++; + + if (result_pos < 0) + { + /* out of frame */ + break; + } + } + + if (string_set_get_size(str_set) == 0) + { + /* no match found in the first row */ + register_reduced_frame_map(winstate, original_pos, RF_UNMATCHED); + return; + } + +#ifdef RPR_DEBUG + elog(DEBUG2, "pos: " INT64_FORMAT " encoded_str: %s", + pos, encoded_str->data); +#endif + + /* build regular expression */ + pattern_str = makeStringInfo(); + appendStringInfoChar(pattern_str, '^'); + initial_index = 0; + + variable_pos = variable_pos_init(); + + forboth(lc1, winstate->patternVariableList, + lc2, winstate->patternRegexpList) + { + char *vname = strVal(lfirst(lc1)); + char *quantifier = strVal(lfirst(lc2)); + char initial; + + initial = pattern_initial(winstate, vname); + Assert(initial != 0); + appendStringInfoChar(pattern_str, initial); + if (quantifier[0]) + appendStringInfoChar(pattern_str, quantifier[0]); + + /* + * Register the initial at initial_index. If the initial appears more + * than once, all of it's initial_index will be recorded. This could + * happen if a pattern variable appears in the PATTERN clause more + * than once like "UP DOWN UP" "UP UP UP". + */ + variable_pos_register(variable_pos, initial, initial_index); + + initial_index++; + } + +#ifdef RPR_DEBUG + elog(DEBUG2, "pos: " INT64_FORMAT " pattern: %s", + pos, pattern_str->data); +#endif + + /* look for matching pattern variable sequence */ +#ifdef RPR_DEBUG + elog(DEBUG1, "search_str_set started"); +#endif + num_matched_rows = search_str_set(pattern_str->data, + str_set, variable_pos); +#ifdef RPR_DEBUG + elog(DEBUG1, "search_str_set returns: %d", num_matched_rows); +#endif + variable_pos_discard(variable_pos); + string_set_discard(str_set); + + /* + * We are at the first row in the reduced frame. Save the number of + * matched rows as the number of rows in the reduced frame. + */ + if (num_matched_rows <= 0) + { + /* no match */ + register_reduced_frame_map(winstate, original_pos, RF_UNMATCHED); + } + else + { + register_reduced_frame_map(winstate, original_pos, RF_FRAME_HEAD); + + for (i = original_pos + 1; i < original_pos + num_matched_rows; i++) + { + register_reduced_frame_map(winstate, i, RF_SKIPPED); + } + } + + return; +} + +/* + * search_str_set + * Perform pattern matching using "pattern" against str_set. pattern is a + * regular expression derived from PATTERN clause. Note that the regular + * expression string is prefixed by '^' and followed by initials represented + * in a same way as str_set. str_set is a set of StringInfo. Each StringInfo + * has a string comprising initials of pattern variable strings being true in + * a row. The initials are one of [a-y], parallel to the order of variable + * names in DEFINE clause. Suppose DEFINE has variables START, UP and DOWN. If + * PATTERN has START, UP+ and DOWN, then the initials in PATTERN will be 'a', + * 'b' and 'c'. The "pattern" will be "^ab+c". + * + * variable_pos is an array representing the order of pattern variable string + * initials in PATTERN clause. For example initial 'a' potion is in + * variable_pos[0].pos[0] = 0. Note that if the pattern is "START UP DOWN UP" + * (UP appears twice), then "UP" (initial is 'b') has two position 1 and + * 3. Thus variable_pos for b is variable_pos[1].pos[0] = 1 and + * variable_pos[1].pos[1] = 3. + * + * Returns the longest number of the matching rows (greedy matching) if + * quatifier '+' or '*' is included in "pattern". + */ +static +int +search_str_set(char *pattern, StringSet * str_set, VariablePos * variable_pos) +{ +#define MAX_CANDIDATE_NUM 10000 /* max pattern match candidate size */ +#define FREEZED_CHAR 'Z' /* a pattern is freezed if it ends with the + * char */ +#define DISCARD_CHAR 'z' /* a pattern is not need to keep */ + + int set_size; /* number of rows in the set */ + int resultlen; + int index; + StringSet *old_str_set, + *new_str_set; + int new_str_size; + int len; + + set_size = string_set_get_size(str_set); + new_str_set = string_set_init(); + len = 0; + resultlen = 0; + + /* + * Generate all possible pattern variable name initials as a set of + * StringInfo named "new_str_set". For example, if we have two rows + * having "ab" (row 0) and "ac" (row 1) in the input str_set, new_str_set + * will have set of StringInfo "aa", "ac", "ba" and "bc" in the end. + */ +#ifdef RPR_DEBUG + elog(DEBUG1, "pattern: %s set_size: %d", pattern, set_size); +#endif + for (index = 0; index < set_size; index++) + { + StringInfo str; /* search target row */ + char *p; + int old_set_size; + int i; + +#ifdef RPR_DEBUG + elog(DEBUG1, "index: %d", index); +#endif + if (index == 0) + { + /* copy variables in row 0 */ + str = string_set_get(str_set, index); + p = str->data; + + /* + * Loop over each new pattern variable char. + */ + while (*p) + { + StringInfo new = makeStringInfo(); + + /* add pattern variable char */ + appendStringInfoChar(new, *p); + /* add new one to string set */ + string_set_add(new_str_set, new); +#ifdef RPR_DEBUG + elog(DEBUG1, "old_str: NULL new_str: %s", new->data); +#endif + p++; /* next pattern variable */ + } + } + else /* index != 0 */ + { + old_str_set = new_str_set; + new_str_set = string_set_init(); + str = string_set_get(str_set, index); + old_set_size = string_set_get_size(old_str_set); + + /* + * Loop over each rows in the previous result set. + */ + for (i = 0; i < old_set_size; i++) + { + StringInfo new; + char last_old_char; + int old_str_len; + StringInfo old = string_set_get(old_str_set, i); + + p = old->data; + old_str_len = strlen(p); + if (old_str_len > 0) + last_old_char = p[old_str_len - 1]; + else + last_old_char = '\0'; + + /* Is this old set freezed? */ + if (last_old_char == FREEZED_CHAR) + { + /* if shorter match. we can discard it */ + if ((old_str_len - 1) < resultlen) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "discard this old set because shorter match: %s", + old->data); +#endif + continue; + } + +#ifdef RPR_DEBUG + elog(DEBUG1, "keep this old set: %s", old->data); +#endif + + /* move the old set to new_str_set */ + string_set_add(new_str_set, old); + old_str_set->str_set[i] = NULL; + continue; + } + /* Can this old set be discarded? */ + else if (last_old_char == DISCARD_CHAR) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "discard this old set: %s", old->data); +#endif + continue; + } + +#ifdef RPR_DEBUG + elog(DEBUG1, "str->data: %s", str->data); +#endif + + /* + * loop over each pattern variable initial char in the input + * set. + */ + for (p = str->data; *p; p++) + { + /* + * Optimization. Check if the row's pattern variable + * initial character position is greater than or equal to + * the old set's last pattern variable initial character + * position. For example, if the old set's last pattern + * variable initials are "ab", then the new pattern + * variable initial can be "b" or "c" but can not be "a", + * if the initials in PATTERN is something like "a b c" or + * "a b+ c+" etc. This optimization is possible when we + * only allow "+" quantifier. + */ + if (variable_pos_compare(variable_pos, last_old_char, *p)) + { + /* copy source string */ + new = makeStringInfo(); + enlargeStringInfo(new, old->len + 1); + appendStringInfoString(new, old->data); + /* add pattern variable char */ + appendStringInfoChar(new, *p); +#ifdef RPR_DEBUG + elog(DEBUG1, "old_str: %s new_str: %s", + old->data, new->data); +#endif + + /* + * Adhoc optimization. If the first letter in the + * input string is the first and second position one + * and there's no associated quatifier '+', then we + * can dicard the input because there's no chace to + * expand the string further. + * + * For example, pattern "abc" cannot match "aa". + */ +#ifdef RPR_DEBUG + elog(DEBUG1, "pattern[1]:%c pattern[2]:%c new[0]:%c new[1]:%c", + pattern[1], pattern[2], new->data[0], new->data[1]); +#endif + if (pattern[1] == new->data[0] && + pattern[1] == new->data[1] && + pattern[2] != '+' && + pattern[1] != pattern[2]) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "discard this new data: %s", + new->data); +#endif + pfree(new->data); + pfree(new); + continue; + } + + /* add new one to string set */ + string_set_add(new_str_set, new); + } + else + { + /* + * We are freezing this pattern string. Since there's + * no chance to expand the string further, we perform + * pattern matching against the string. If it does not + * match, we can discard it. + */ + len = do_pattern_match(pattern, old->data); + + if (len <= 0) + { + /* no match. we can discard it */ + continue; + } + + else if (len <= resultlen) + { + /* shorter match. we can discard it */ + continue; + } + else + { + /* match length is the longest so far */ + + int new_index; + + /* remember the longest match */ + resultlen = len; + + /* freeze the pattern string */ + new = makeStringInfo(); + enlargeStringInfo(new, old->len + 1); + appendStringInfoString(new, old->data); + /* add freezed mark */ + appendStringInfoChar(new, FREEZED_CHAR); +#ifdef RPR_DEBUG + elog(DEBUG1, "old_str: %s new_str: %s", old->data, new->data); +#endif + string_set_add(new_str_set, new); + + /* + * Search new_str_set to find out freezed entries + * that have shorter match length. Mark them as + * "discard" so that they are discarded in the + * next round. + */ + + /* new_index_size should be the one before */ + new_str_size = + string_set_get_size(new_str_set) - 1; + + /* loop over new_str_set */ + for (new_index = 0; new_index < new_str_size; + new_index++) + { + char new_last_char; + int new_str_len; + + new = string_set_get(new_str_set, new_index); + new_str_len = strlen(new->data); + if (new_str_len > 0) + { + new_last_char = + new->data[new_str_len - 1]; + if (new_last_char == FREEZED_CHAR && + (new_str_len - 1) <= len) + { + /* + * mark this set to discard in the + * next round + */ + appendStringInfoChar(new, DISCARD_CHAR); +#ifdef RPR_DEBUG + elog(DEBUG1, "add discard char: %s", new->data); +#endif + } + } + } + } + } + } + } + /* we no longer need old string set */ + string_set_discard(old_str_set); + } + } + + /* + * Perform pattern matching to find out the longest match. + */ + new_str_size = string_set_get_size(new_str_set); +#ifdef RPR_DEBUG + elog(DEBUG1, "new_str_size: %d", new_str_size); +#endif + len = 0; + resultlen = 0; + + for (index = 0; index < new_str_size; index++) + { + StringInfo s; + + s = string_set_get(new_str_set, index); + if (s == NULL) + continue; /* no data */ + +#ifdef RPR_DEBUG + elog(DEBUG1, "target string: %s", s->data); +#endif + len = do_pattern_match(pattern, s->data); + if (len > resultlen) + { + /* remember the longest match */ + resultlen = len; + + /* + * If the size of result set is equal to the number of rows in the + * set, we are done because it's not possible that the number of + * matching rows exceeds the number of rows in the set. + */ + if (resultlen >= set_size) + break; + } + } + + /* we no longer need new string set */ + string_set_discard(new_str_set); + + return resultlen; +} + +/* + * do_pattern_match + * perform pattern match using pattern against encoded_str. + * returns matching number of rows if matching is succeeded. + * Otherwise returns 0. + */ +static +int +do_pattern_match(char *pattern, char *encoded_str) +{ + Datum d; + text *res; + char *substr; + int len = 0; + text *pattern_text, + *encoded_str_text; + + pattern_text = cstring_to_text(pattern); + encoded_str_text = cstring_to_text(encoded_str); + + /* + * We first perform pattern matching using regexp_instr, then call + * textregexsubstr to get matched substring to know how long the matched + * string is. That is the number of rows in the reduced window frame. The + * reason why we can't call textregexsubstr in the first place is, it + * errors out if pattern does not match. + */ + if (DatumGetInt32(DirectFunctionCall2Coll( + regexp_instr, DEFAULT_COLLATION_OID, + PointerGetDatum(encoded_str_text), + PointerGetDatum(pattern_text)))) + { + d = DirectFunctionCall2Coll(textregexsubstr, + DEFAULT_COLLATION_OID, + PointerGetDatum(encoded_str_text), + PointerGetDatum(pattern_text)); + if (d != 0) + { + res = DatumGetTextPP(d); + substr = text_to_cstring(res); + len = strlen(substr); + pfree(substr); + } + } + pfree(encoded_str_text); + pfree(pattern_text); + + return len; +} + +/* + * evaluate_pattern + * Evaluate expression associated with PATTERN variable vname. current_pos is + * relative row position in a frame (starting from 0). If vname is evaluated + * to true, initial letters associated with vname is appended to + * encode_str. result is out paramater representing the expression evaluation + * result is true of false. + *--------- + * Return values are: + * >=0: the last match absolute row position + * otherwise out of frame. + *--------- + */ +static +int64 +evaluate_pattern(WindowObject winobj, int64 current_pos, + char *vname, StringInfo encoded_str, bool *result) +{ + WindowAggState *winstate = winobj->winstate; + ExprContext *econtext = winstate->ss.ps.ps_ExprContext; + ListCell *lc1, + *lc2, + *lc3; + ExprState *pat; + Datum eval_result; + bool out_of_frame = false; + bool isnull; + TupleTableSlot *slot; + + forthree(lc1, winstate->defineVariableList, + lc2, winstate->defineClauseList, + lc3, winstate->defineInitial) + { + char initial; /* initial letter associated with vname */ + char *name = strVal(lfirst(lc1)); + + if (strcmp(vname, name)) + continue; + + initial = *(strVal(lfirst(lc3))); + + /* set expression to evaluate */ + pat = lfirst(lc2); + + /* get current, previous and next tuples */ + if (!get_slots(winobj, current_pos)) + { + out_of_frame = true; + } + else + { + /* evaluate the expression */ + eval_result = ExecEvalExpr(pat, econtext, &isnull); + if (isnull) + { + /* expression is NULL */ +#ifdef RPR_DEBUG + elog(DEBUG1, "expression for %s is NULL at row: " INT64_FORMAT, + vname, current_pos); +#endif + *result = false; + } + else + { + if (!DatumGetBool(eval_result)) + { + /* expression is false */ +#ifdef RPR_DEBUG + elog(DEBUG1, "expression for %s is false at row: " INT64_FORMAT, + vname, current_pos); +#endif + *result = false; + } + else + { + /* expression is true */ +#ifdef RPR_DEBUG + elog(DEBUG1, "expression for %s is true at row: " INT64_FORMAT, + vname, current_pos); +#endif + appendStringInfoChar(encoded_str, initial); + *result = true; + } + } + + slot = winstate->temp_slot_1; + if (slot != winstate->null_slot) + ExecClearTuple(slot); + slot = winstate->prev_slot; + if (slot != winstate->null_slot) + ExecClearTuple(slot); + slot = winstate->next_slot; + if (slot != winstate->null_slot) + ExecClearTuple(slot); + + break; + } + + if (out_of_frame) + { + *result = false; + return -1; + } + } + return current_pos; +} + +/* + * get_slots + * Get current, previous and next tuples. + * Returns false if current row is out of partition/full frame. + */ +static +bool +get_slots(WindowObject winobj, int64 current_pos) +{ + WindowAggState *winstate = winobj->winstate; + TupleTableSlot *slot; + int ret; + ExprContext *econtext; + + econtext = winstate->ss.ps.ps_ExprContext; + + /* set up current row tuple slot */ + slot = winstate->temp_slot_1; + if (!window_gettupleslot(winobj, current_pos, slot)) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "current row is out of partition at:" INT64_FORMAT, + current_pos); +#endif + return false; + } + ret = row_is_in_frame(winstate, current_pos, slot); + if (ret <= 0) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "current row is out of frame at: " INT64_FORMAT, + current_pos); +#endif + ExecClearTuple(slot); + return false; + } + econtext->ecxt_outertuple = slot; + + /* for PREV */ + if (current_pos > 0) + { + slot = winstate->prev_slot; + if (!window_gettupleslot(winobj, current_pos - 1, slot)) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "previous row is out of partition at: " INT64_FORMAT, + current_pos - 1); +#endif + econtext->ecxt_scantuple = winstate->null_slot; + } + else + { + ret = row_is_in_frame(winstate, current_pos - 1, slot); + if (ret <= 0) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "previous row is out of frame at: " INT64_FORMAT, + current_pos - 1); +#endif + ExecClearTuple(slot); + econtext->ecxt_scantuple = winstate->null_slot; + } + else + { + econtext->ecxt_scantuple = slot; + } + } + } + else + econtext->ecxt_scantuple = winstate->null_slot; + + /* for NEXT */ + slot = winstate->next_slot; + if (!window_gettupleslot(winobj, current_pos + 1, slot)) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "next row is out of partiton at: " INT64_FORMAT, + current_pos + 1); +#endif + econtext->ecxt_innertuple = winstate->null_slot; + } + else + { + ret = row_is_in_frame(winstate, current_pos + 1, slot); + if (ret <= 0) + { +#ifdef RPR_DEBUG + elog(DEBUG1, "next row is out of frame at: " INT64_FORMAT, + current_pos + 1); +#endif + ExecClearTuple(slot); + econtext->ecxt_innertuple = winstate->null_slot; + } + else + econtext->ecxt_innertuple = slot; + } + return true; +} + +/* + * pattern_initial + * Return pattern variable initial character + * matching with pattern variable name vname. + * If not found, return 0. + */ +static +char +pattern_initial(WindowAggState *winstate, char *vname) +{ + char initial; + char *name; + ListCell *lc1, + *lc2; + + forboth(lc1, winstate->defineVariableList, + lc2, winstate->defineInitial) + { + name = strVal(lfirst(lc1)); /* DEFINE variable name */ + initial = *(strVal(lfirst(lc2))); /* DEFINE variable initial */ + + + if (!strcmp(name, vname)) + return initial; /* found */ + } + return 0; +} + +/* + * string_set_init + * Create dynamic set of StringInfo. + */ +static +StringSet * string_set_init(void) +{ +/* Initial allocation size of str_set */ +#define STRING_SET_ALLOC_SIZE 1024 + + StringSet *string_set; + Size set_size; + + string_set = palloc0(sizeof(StringSet)); + string_set->set_index = 0; + set_size = STRING_SET_ALLOC_SIZE; + string_set->str_set = palloc(set_size * sizeof(StringInfo)); + string_set->set_size = set_size; + + return string_set; +} + +/* + * string_set_add + * Add StringInfo str to StringSet string_set. + */ +static +void +string_set_add(StringSet * string_set, StringInfo str) +{ + Size set_size; + + set_size = string_set->set_size; + if (string_set->set_index >= set_size) + { + set_size *= 2; + string_set->str_set = repalloc(string_set->str_set, + set_size * sizeof(StringInfo)); + string_set->set_size = set_size; + } + + string_set->str_set[string_set->set_index++] = str; + + return; +} + +/* + * string_set_get + * Returns StringInfo specified by index. + * If there's no data yet, returns NULL. + */ +static +StringInfo +string_set_get(StringSet * string_set, int index) +{ + /* no data? */ + if (index == 0 && string_set->set_index == 0) + return NULL; + + if (index < 0 || index >= string_set->set_index) + elog(ERROR, "invalid index: %d", index); + + return string_set->str_set[index]; +} + +/* + * string_set_get_size + * Returns the size of StringSet. + */ +static +int +string_set_get_size(StringSet * string_set) +{ + return string_set->set_index; +} + +/* + * string_set_discard + * Discard StringSet. + * All memory including StringSet itself is freed. + */ +static +void +string_set_discard(StringSet * string_set) +{ + int i; + + for (i = 0; i < string_set->set_index; i++) + { + StringInfo str = string_set->str_set[i]; + + if (str) + { + pfree(str->data); + pfree(str); + } + } + pfree(string_set->str_set); + pfree(string_set); +} + +/* + * variable_pos_init + * Create and initialize variable postion structure + */ +static +VariablePos * variable_pos_init(void) +{ + VariablePos *variable_pos; + + variable_pos = palloc(sizeof(VariablePos) * NUM_ALPHABETS); + MemSet(variable_pos, -1, sizeof(VariablePos) * NUM_ALPHABETS); + return variable_pos; +} + +/* + * variable_pos_register + * Register pattern variable whose initial is initial into postion index. + * pos is position of initial. + * If pos is already registered, register it at next empty slot. + */ +static +void +variable_pos_register(VariablePos * variable_pos, char initial, int pos) +{ + int index = initial - 'a'; + int slot; + int i; + + if (pos < 0 || pos > NUM_ALPHABETS) + elog(ERROR, "initial is not valid char: %c", initial); + + for (i = 0; i < NUM_ALPHABETS; i++) + { + slot = variable_pos[index].pos[i]; + if (slot < 0) + { + /* empty slot found */ + variable_pos[index].pos[i] = pos; + return; + } + } + elog(ERROR, "no empty slot for initial: %c", initial); +} + +/* + * variable_pos_compare + * Returns true if initial1 can be followed by initial2 + */ +static +bool +variable_pos_compare(VariablePos * variable_pos, char initial1, char initial2) +{ + int index1, + index2; + int pos1, + pos2; + + for (index1 = 0;; index1++) + { + pos1 = variable_pos_fetch(variable_pos, initial1, index1); + if (pos1 < 0) + break; + + for (index2 = 0;; index2++) + { + pos2 = variable_pos_fetch(variable_pos, initial2, index2); + if (pos2 < 0) + break; + if (pos1 <= pos2) + return true; + } + } + return false; +} + +/* + * variable_pos_fetch + * Fetch position of pattern variable whose initial is initial, and whose index + * is index. If no postion was registered by initial, index, returns -1. + */ +static +int +variable_pos_fetch(VariablePos * variable_pos, char initial, int index) +{ + int pos = initial - 'a'; + + if (pos < 0 || pos > NUM_ALPHABETS) + elog(ERROR, "initial is not valid char: %c", initial); + + if (index < 0 || index > NUM_ALPHABETS) + elog(ERROR, "index is not valid: %d", index); + + return variable_pos[pos].pos[index]; +} + +/* + * variable_pos_discard + * Discard VariablePos + */ +static +void +variable_pos_discard(VariablePos * variable_pos) +{ + pfree(variable_pos); +} diff --git a/src/backend/utils/adt/windowfuncs.c b/src/backend/utils/adt/windowfuncs.c index 473c61569f..92c528d38c 100644 --- a/src/backend/utils/adt/windowfuncs.c +++ b/src/backend/utils/adt/windowfuncs.c @@ -13,6 +13,9 @@ */ #include "postgres.h" +#include "catalog/pg_collation_d.h" +#include "executor/executor.h" +#include "nodes/execnodes.h" #include "nodes/parsenodes.h" #include "nodes/supportnodes.h" #include "utils/fmgrprotos.h" @@ -37,11 +40,19 @@ typedef struct int64 remainder; /* (total rows) % (bucket num) */ } ntile_context; +/* + * rpr process information. + * Used for AFTER MATCH SKIP PAST LAST ROW + */ +typedef struct SkipContext +{ + int64 pos; /* last row absolute position */ +} SkipContext; + static bool rank_up(WindowObject winobj); static Datum leadlag_common(FunctionCallInfo fcinfo, bool forward, bool withoffset, bool withdefault); - /* * utility routine for *_rank functions. */ @@ -674,7 +685,7 @@ window_last_value(PG_FUNCTION_ARGS) bool isnull; result = WinGetFuncArgInFrame(winobj, 0, - 0, WINDOW_SEEK_TAIL, true, + 0, WINDOW_SEEK_TAIL, false, &isnull, NULL); if (isnull) PG_RETURN_NULL(); @@ -714,3 +725,25 @@ window_nth_value(PG_FUNCTION_ARGS) PG_RETURN_DATUM(result); } + +/* + * prev + * Dummy function to invoke RPR's navigation operator "PREV". + * This is *not* a window function. + */ +Datum +window_prev(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(PG_GETARG_DATUM(0)); +} + +/* + * next + * Dummy function to invoke RPR's navigation operation "NEXT". + * This is *not* a window function. + */ +Datum +window_next(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(PG_GETARG_DATUM(0)); +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 4abc6d9526..c3fafed291 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -10549,6 +10549,12 @@ { oid => '3114', descr => 'fetch the Nth row value', proname => 'nth_value', prokind => 'w', prorettype => 'anyelement', proargtypes => 'anyelement int4', prosrc => 'window_nth_value' }, +{ oid => '6122', descr => 'previous value', + proname => 'prev', provolatile => 's', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_prev' }, +{ oid => '6123', descr => 'next value', + proname => 'next', provolatile => 's', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_next' }, # functions for range types { oid => '3832', descr => 'I/O', diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index af7d8fd1e7..609b066845 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2578,6 +2578,11 @@ typedef enum WindowAggStatus * tuples during spool */ } WindowAggStatus; +#define RF_NOT_DETERMINED 0 +#define RF_FRAME_HEAD 1 +#define RF_SKIPPED 2 +#define RF_UNMATCHED 3 + typedef struct WindowAggState { ScanState ss; /* its first field is NodeTag */ @@ -2626,6 +2631,19 @@ typedef struct WindowAggState int64 groupheadpos; /* current row's peer group head position */ int64 grouptailpos; /* " " " " tail position (group end+1) */ + /* these fields are used in Row pattern recognition: */ + RPSkipTo rpSkipTo; /* Row Pattern Skip To type */ + List *patternVariableList; /* list of row pattern variables names + * (list of String) */ + List *patternRegexpList; /* list of row pattern regular expressions + * ('+' or ''. list of String) */ + List *defineVariableList; /* list of row pattern definition + * variables (list of String) */ + List *defineClauseList; /* expression for row pattern definition + * search conditions ExprState list */ + List *defineInitial; /* list of row pattern definition variable + * initials (list of String) */ + MemoryContext partcontext; /* context for partition-lifespan data */ MemoryContext aggcontext; /* shared context for aggregate working data */ MemoryContext curaggcontext; /* current aggregate's working data */ @@ -2662,6 +2680,18 @@ typedef struct WindowAggState TupleTableSlot *agg_row_slot; TupleTableSlot *temp_slot_1; TupleTableSlot *temp_slot_2; + + /* temporary slots for RPR */ + TupleTableSlot *prev_slot; /* PREV row navigation operator */ + TupleTableSlot *next_slot; /* NEXT row navigation operator */ + TupleTableSlot *null_slot; /* all NULL slot */ + + /* + * Each byte corresponds to a row positioned at absolute its pos in + * partition. See above definition for RF_* + */ + char *reduced_frame_map; + int64 alloc_sz; /* size of the map */ } WindowAggState; /* ---------------- -- 2.25.1 ----Next_Part(Mon_Aug_26_13_39_47_2024_878)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v21-0006-Row-pattern-recognition-patch-docs.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
* [PATCH v6a 1/5] Add GitHub Actions workflow for CI @ 2026-05-28 16:31 Nazir Bilal Yavuz <[email protected]> 0 siblings, 0 replies; 153+ messages in thread From: Nazir Bilal Yavuz @ 2026-05-28 16:31 UTC (permalink / raw) Cirrus CI, which the project has used to run CI, is shutting down on June 1, 2026. Replace it with a GitHub Actions. Github Actions is selected because it has unlimited runner time for public repositories. Github Action currently covers: - SanityCheck - Linux (Autoconf) - Linux (Meson, 32- and 64-bit) - macOS (Meson) - Windows (Visual Studio + Meson and MinGW + Meson) - CompilerWarnings BSD coverage is left for later, as it requires more work. Back-branches will be updated later, after being sure that workflow runs correctly on master. Author: Jelte Fennema-Nio <[email protected]> Author: Nazir Bilal Yavuz <[email protected]> Reviewed-by: Jacob Champion <[email protected]> Reviewed-by: Peter Eisentraut <[email protected]> Reviewed-by: Andres Freund <[email protected]> Reviewed-by: Zsolt Parragi <[email protected]> Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm --- .github/workflows/postgresql-ci.yml | 1026 ++++++++++++++++++++++++++ src/tools/ci/ci_macports_packages.sh | 19 +- 2 files changed, 1042 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/postgresql-ci.yml diff --git a/.github/workflows/postgresql-ci.yml b/.github/workflows/postgresql-ci.yml new file mode 100644 index 00000000000..a7ef0bee94d --- /dev/null +++ b/.github/workflows/postgresql-ci.yml @@ -0,0 +1,1026 @@ +# GitHub Actions CI configuration for PostgreSQL + +name: GitHub Actions CI + +on: + push: + +# Restrict GITHUB_TOKEN to the minimum the jobs need: reading repo +# contents during checkout. +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + # Never cancel in-progress runs on master to ensure all commits are tested. + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + # The lower depth accelerates git clone. Use a bit of depth so that + # concurrent jobs and retrying older runs have a chance of working. + CLONE_DEPTH: 500 + + CCACHE_MAXSIZE: "250M" + + # check target for the autoconf builds + CHECK: check-world PROVE_FLAGS=--timer + CHECKFLAGS: -Otarget + + # Build test dependencies as part of the build step, to see compiler + # errors/warnings in one place. + MBUILD_TARGET: all testprep + MTEST_ARGS: --print-errorlogs --no-rebuild -C build + PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests + TEMP_CONFIG: ${{ github.workspace }}/src/tools/ci/pg_ci_base.conf + PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth + + # Postgres config args for the meson builds, shared between all meson tasks + # except the 'SanityCheck' task + MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true + + # Meson feature flags shared by all meson tasks, except: + # SanityCheck: uses almost no dependencies. + # Windows - VS: has fewer dependencies than listed here, so defines its own. + # Linux: uses the 'auto' feature option to test meson feature autodetection. + MESON_COMMON_FEATURES: >- + -Dauto_features=disabled + -Dldap=enabled + -Dssl=openssl + -Dtap_tests=enabled + -Dplperl=enabled + -Dplpython=enabled + -Ddocs=enabled + -Dicu=enabled + -Dlibxml=enabled + -Dlibxslt=enabled + -Dlz4=enabled + -Dpltcl=enabled + -Dreadline=enabled + -Dzlib=enabled + -Dzstd=enabled + + # Shared between the Linux autoconf job and the CompilerWarnings jobs + LINUX_CONFIGURE_FEATURES: >- + --with-gssapi + --with-icu + --with-ldap + --with-libcurl + --with-libxml + --with-libxslt + --with-llvm + --with-lz4 + --with-pam + --with-perl + --with-python + --with-selinux + --with-ssl=openssl + --with-systemd + --with-tcl --with-tclconfig=/usr/lib/tcl8.6/ + --with-uuid=ossp + --with-zstd + + # Debian Trixie container image used by all Linux jobs. Built by + # 'https://github.com/anarazel/pg-vm-images/';. + LINUX_CI_IMAGE: us-docker.pkg.dev/pg-ci-images/ci/linux_debian_trixie_ci:latest + + # The full set of OS / job selectors recognized by the `ci-os-only:` + # commit-message directive parsed in the `setup` job below. + CI_OS_ONLY_JOBS: "linux macos windows mingw compilerwarnings sanitycheck" + + _LOG_PATHS: &log_paths | + build*/testrun/**/*.log + build*/testrun/**/*.diffs + build*/testrun/**/regress_log_* + build*/meson-logs/*.txt + + +jobs: + # Parse "ci-os-only: ..." from the commit message and expose flags + # consumed by the jobs' `if:` conditions. + setup: + name: Determine enabled jobs + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + linux: ${{ steps.os.outputs.linux }} + macos: ${{ steps.os.outputs.macos }} + windows: ${{ steps.os.outputs.windows }} + mingw: ${{ steps.os.outputs.mingw }} + compilerwarnings: ${{ steps.os.outputs.compilerwarnings }} + sanitycheck: ${{ steps.os.outputs.sanitycheck }} + # Re-export workflow-level env vars that other jobs need to reference + # from contexts (e.g. `jobs.<id>.container.image`) where the `env` + # context is not available. + linux_ci_image: ${{ env.LINUX_CI_IMAGE }} + steps: + - id: os + env: + MSG: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -e + all_os=${CI_OS_ONLY_JOBS} + if printf '%s\n' "$MSG" | grep -qE '^ci-os-only: '; then + sel=$(printf '%s\n' "$MSG" | sed -n 's/^ci-os-only: //p' | head -n 1) + echo "ci-os-only selection: $sel" + else + sel="$all_os" + fi + for o in $all_os; do + if echo " $sel " | grep -qE "[ ,]$o[ ,]"; then + echo "$o=true" >> "$GITHUB_OUTPUT" + else + echo "$o=false" >> "$GITHUB_OUTPUT" + fi + done + cat "$GITHUB_OUTPUT" + + + # To avoid unnecessarily spinning up a lot of VMs / containers for entirely + # broken commits, have a minimal task that all others depend on. + # + # SPECIAL: + # - Builds with --auto-features=disabled and thus almost no enabled + # dependencies + sanity-check: + name: SanityCheck + needs: setup + if: needs.setup.outputs.sanitycheck == 'true' + runs-on: ubuntu-latest + timeout-minutes: 15 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern. + options: --privileged + env: + BUILD_JOBS: 8 + TEST_JOBS: 8 + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + # no options enabled, should be small + CCACHE_MAXSIZE: "150M" + steps: + # Anchor reused by other jobs further down. GitHub Actions supports + # YAML anchors/aliases but not merge keys, so the alias copies the + # whole step verbatim. The anchor is resolved at YAML parse time, so the + # alias keeps working even if this job is skipped at runtime. + - &checkout_step + uses: actions/checkout@v6 + with: + fetch-depth: ${{ env.CLONE_DEPTH }} + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-sanitycheck-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-sanitycheck-${{ github.ref_name }}- + ccache-sanitycheck- + + - name: Prepare workspace + run: | + whoami + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + + - name: Configure + run: | + su postgres <<-'EOF' + set -e + meson setup \ + --buildtype=debug \ + --auto-features=disabled \ + -Ddefault_library=shared \ + -Dtap_tests=enabled \ + build + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + EOF + + # Run a minimal set of tests. The main regression tests take too long + # for this purpose. For now this is a random quick pg_regress style + # test, and a tap test that exercises both a frontend binary and the + # backend. + - name: Test + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + meson test ${MTEST_ARGS} --suite setup + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} \ + cube/regress pg_ctl/001_start_stop + EOF + + - name: Core backtraces + if: failure() + run: | + mkdir -m 770 /tmp/cores + find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \; + src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: sanitycheck-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + # Build & test postgres on Linux in three configurations. + # + # Autoconf: + # - Uses address sanitizer (sanitizer failures are typically printed in + # the server log) + # - Configures postgres with a small segment size + # - Uses PG_TEST_PG_COMBINEBACKUP_MODE=--copy-file-range + # + # Meson: + # - Test both 64- and 32-bit builds + # - Uses undefined behaviour and alignment sanitizers, (sanitizer failures + # are typically printed in the server log) + # - Uses io_method=io_uring + # - Uses meson feature autodetection + # - 32-bit build tests with LANG=C to give ICU some buildfarm-uncovered + # coverage. Also, newer Python insists on changing LC_CTYPE away from C, + # prevent that with PYTHONCOERCECLOCALE. + # + # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes + # print_stacktraces=1,verbosity=2, duh + # detect_leaks=0: too many uninteresting leak errors in short-lived binaries + linux: + name: Linux - ${{ matrix.name }} + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.linux == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - name: Autoconf + slug: autoconf + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=address + pg_test_pg_combinebackup_mode: '--copy-file-range' + configure: | + ./configure \ + --enable-cassert --enable-injection-points --enable-debug \ + --enable-tap-tests --enable-nls \ + --with-segsize-blocks=6 \ + --with-libnuma \ + --with-liburing \ + ${LINUX_CONFIGURE_FEATURES} \ + CLANG="ccache clang" + build: | + make -s -j${BUILD_JOBS} world-bin + test: | + make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS} + logs_paths: | + **/*.log + **/*.diffs + **/regress_log_* + + - name: Meson (64-bit) + slug: meson-64 + cc: ccache gcc + cxx: ccache g++ + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + -Dllvm=enabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + + - name: Meson (32-bit) + slug: meson-32 + cc: ccache gcc -m32 + cxx: ccache g++ -m32 + sanitizer_flags: -fsanitize=alignment,undefined + pg_test_initdb_extra_opts: '-c io_method=io_uring' + configure: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Duuid=e2fs \ + --buildtype=debug \ + --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \ + -DPERL=perl5.40-i386-linux-gnu \ + -Dlibnuma=disabled \ + build + build: | + ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + ninja -C build -t missingdeps + test: | + PYTHONCOERCECLOCALE=0 LANG=C \ + meson test ${MTEST_ARGS} -C build --num-processes ${TEST_JOBS} + logs_paths: *log_paths + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + # Share the host PID + IPC namespaces. 017_shm.pl rapidly creates, + # kill9's, and restarts postgres; with the container's small PID + # space a new postgres can recycle the dead postmaster's PID before + # pg_ctl's postmaster.pid check notices, producing spurious "node X + # is already running" failures. SysV shm in the test also relies on + # host-like IPC behavior. + # + # --ulimit raises memlock and core dump size. Memlock is needed for + # running the AIO tests. + # + # --privileged is needed so the prepare step can write to sysctls + # under /proc/sys (it's mounted read-only without it). We use it to + # set kernel.core_pattern and (for the meson entries) to flip + # kernel.io_uring_disabled (default 2 on recent GH runner kernels). + options: --pid=host --ipc=host --ulimit memlock=-1:-1 --privileged + env: + BUILD_JOBS: 4 + TEST_JOBS: 8 + CCACHE_DIR: /tmp/ccache_dir + DEBUGINFOD_URLS: "https://debuginfod.debian.net"; + + UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2 + ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0 + CFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + CXXFLAGS: -Og -ggdb -fno-sanitize-recover=all ${{ matrix.sanitizer_flags }} + LDFLAGS: ${{ matrix.sanitizer_flags }} + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + PG_TEST_INITDB_EXTRA_OPTS: ${{ matrix.pg_test_initdb_extra_opts }} + PG_TEST_PG_COMBINEBACKUP_MODE: ${{ matrix.pg_test_pg_combinebackup_mode }} + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-linux-${{ matrix.slug }}-${{ github.ref_name }}- + ccache-linux-${{ matrix.slug }}- + + - name: Prepare workspace + run: | + useradd -m postgres + chown -R postgres:postgres . + mkdir -p "$CCACHE_DIR" + chown -R postgres:postgres "$CCACHE_DIR" + mkdir -m 770 /tmp/cores + chown root:postgres /tmp/cores + sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core' + # This is only needed on Linux Meson but it doesn't harm to have + # this enabled. + sysctl -w kernel.io_uring_disabled=0 + + cat >> /etc/hosts <<-EOF + 127.0.0.1 pg-loadbalancetest + 127.0.0.2 pg-loadbalancetest + 127.0.0.3 pg-loadbalancetest + EOF + + - name: Configure + run: | + su postgres <<EOF + set -e + ${{ matrix.configure }} + EOF + + - name: Build + run: | + su postgres <<EOF + set -e + ${{ matrix.build }} + EOF + + - name: Test world + run: | + su postgres <<EOF + set -e + ulimit -c unlimited + ${{ matrix.test }} + EOF + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh linux /tmp/cores + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: linux-${{ matrix.slug }}-logs-${{ github.run_id }} + path: ${{ matrix.logs_paths }} + if-no-files-found: ignore + + + # SPECIAL: + # - Enables --clone for pg_upgrade and pg_combinebackup + # - Specifies configuration options that test reading/writing/copying of node trees + # - Specifies debug_parallel_query=regress, to catch related issues during CI + macos: + name: macOS - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.macos == 'true' && + needs.sanity-check.result != 'failure' + runs-on: macos-15 + timeout-minutes: 60 + env: + BUILD_JOBS: 4 + # Test performance regresses noticeably when using all cores. 8 works OK. + # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de + # Fix: Needs to be re-tested for GitHub Actions. + TEST_JOBS: 8 + + CCACHE_DIR: ${{ github.workspace }}/ccache_dir + MACPORTS_CACHE: ${{ github.workspace }}/macports-cache + + MESON_FEATURES: >- + -Dbonjour=enabled + -Ddtrace=enabled + -Dgssapi=enabled + -Dlibcurl=enabled + -Dnls=enabled + -Duuid=e2fs + + MACOS_PACKAGE_LIST: >- + ccache + icu + kerberos5 + lz4 + meson + openldap + openssl + p5.34-io-tty + p5.34-ipc-run + python312 + tcl + zstd + + CC: ccache cc + CXX: ccache c++ + CFLAGS: -Og -ggdb + CXXFLAGS: -Og -ggdb + PG_TEST_PG_UPGRADE_MODE: --clone + PG_TEST_PG_COMBINEBACKUP_MODE: --clone + + # Several buildfarm animals enable these options. Without testing them + # during CI, it would be easy to cause breakage on the buildfarm with CI + # passing. + PG_TEST_INITDB_EXTRA_OPTS: >- + -c debug_copy_parse_plan_trees=on + -c debug_write_read_parse_plan_trees=on + -c debug_raw_expression_coverage_test=on + -c debug_parallel_query=regress + + steps: + - *checkout_step + + - name: Sysinfo + run: | + id + uname -a + ulimit -a -H && ulimit -a -S + env + + - name: Setup core files + run: | + mkdir -p $HOME/cores + sudo sysctl kern.corefile="$HOME/cores/core.%P" + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-macos-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-macos-${{ github.ref_name }}- + ccache-macos- + + - name: Compute MacPorts cache key + id: mpkey + run: | + macos_major=$(sw_vers -productVersion | sed 's/\..*//') + pkglist_hash=$(printf '%s' "$MACOS_PACKAGE_LIST" | md5 -q) + script_hash=$(md5 -q src/tools/ci/ci_macports_packages.sh) + echo "key=macports-${macos_major}-${pkglist_hash}-${script_hash}-${GITHUB_RUN_ID}" >> "$GITHUB_OUTPUT" + echo "restore-key=macports-${macos_major}-${pkglist_hash}-${script_hash}-" >> "$GITHUB_OUTPUT" + + - name: Restore MacPorts cache + uses: actions/cache@v5 + with: + path: ${{ env.MACPORTS_CACHE }} + key: ${{ steps.mpkey.outputs.key }} + restore-keys: ${{ steps.mpkey.outputs.restore-key }} + + # Use MacPorts, even though Homebrew is installed. The installation + # of the additional packages we need would take quite a while with + # Homebrew, even if we cache the downloads. We can't cache all of + # Homebrew, because it's already large. So we use MacPorts. To cache + # the installation we create a .dmg file that we mount if it already + # exists. + # XXX: The reason for the direct p5.34* references is that we'd need + # the large MacPort tree around to figure out that p5-io-tty is + # actually p5.34-io-tty. Using the unversioned name works, but + # updates MacPorts every time. + - name: Install dependencies (MacPorts) + env: + # Pass token so the script's GitHub API call to list MacPorts + # releases isn't subject to the 60/h/IP unauthenticated rate + # limit (shared across all jobs on the runner's IP). + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST + # system python doesn't provide headers + sudo /opt/local/bin/port select python3 python312 + # Make macports install visible to subsequent steps + echo /opt/local/sbin >> "$GITHUB_PATH" + echo /opt/local/bin >> "$GITHUB_PATH" + + - name: Configure + run: | + export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/" + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + --buildtype=debug \ + -Dextra_include_dirs=/opt/local/include \ + -Dextra_lib_dirs=/opt/local/lib \ + -Ddarwin_sysroot=none \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + build + + - name: Build + run: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET} + + - name: Test world + run: | + ulimit -c unlimited # default is 0 + ulimit -n 1024 # default is 256, pretty low + meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + - name: Core backtraces + if: failure() + run: src/tools/ci/cores_backtrace.sh macos "$HOME/cores" + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: macos-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-vs: + name: Windows - VS - Meson & ninja + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.windows == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 8 + # Avoid port conflicts between concurrent tap tests + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + + MESON_FEATURES: >- + -Dcpp_args=/std:c++20 + -Dauto_features=disabled + -Dtap_tests=enabled + -Dldap=enabled + -Dssl=openssl + -Dplperl=enabled + -Dplpython=enabled + TAR: "c:/windows/system32/tar.exe" + + defaults: + run: + shell: cmd + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + - name: Sysinfo + run: | + chcp + systeminfo + set + + # The TAP tests build an initdb template under build/tmp_install and + # then `robocopy` it into per-test data directories. Robocopy with the + # default /COPY:DAT flag doesn't copy ACLs — destinations inherit from + # their parent dir. On GitHub-hosted Windows runners the workspace's + # inherited ACL grants Administrators:(F) and Users:(RX) but does NOT + # grant the runner user (runneradmin) directly. That matters because + # pg_ctl on Windows uses CreateRestrictedProcess to drop admin + # privileges from postmaster, so the postmaster process has the user + # SID in its token but no longer the Administrators group — leaving it + # with only "Users:(RX)" on pg_control and friends, which causes + # "PANIC: could not open file global/pg_control: Permission denied". + # + # Fix it once on the workspace dir with (OI)(CI) inheritance flags so + # every file/dir created underneath gets an explicit grant for the + # current user. + - name: Grant workspace ACL to runner user + shell: pwsh + run: | + icacls "${{ github.workspace }}" /grant "${env:USERNAME}:(OI)(CI)F" /Q | Out-Null + Write-Host "Granted Full Control to $env:USERNAME on ${{ github.workspace }}" + + # postgres' plpython3u loads python3.dll (the stable-ABI forwarder) + # which in turn loads whichever python3NN.dll the Windows loader finds + # first on PATH. On windows-2022 `C:\Program Files\Mercurial\` ships + # its own python3.dll + python39.dll and appears on PATH *before* the + # hostedtoolcache Python 3.12 — so without intervention the backend + # ends up running Python 3.9 while postgres' stdlib search uses 3.12, + # producing `ImportError: cannot import name 'text_encoding' from + # 'io'` (the 3.12 `io.py` calling into 3.9's `_io`). + # + # Drop Mercurial's directory from PATH so the hostedtoolcache + # python3.dll wins the DLL search. + - name: Remove Mercurial from PATH + shell: pwsh + run: | + $filtered = ($env:PATH -split ';' | + Where-Object { $_ -and ($_ -notmatch '\\Mercurial\\?$') }) -join ';' + Add-Content $env:GITHUB_ENV "PATH=$filtered" + Write-Host "Removed Mercurial entries from PATH" + + - name: Install dependencies + shell: pwsh + run: | + choco install -y --no-progress --limitoutput diffutils winflexbison3 + # meson + ninja aren't preinstalled on windows-2022. Install via pip + python -m pip install --upgrade meson ninja + + # OpenSSL 1.1 via the slproweb installer (pinned to match the + # version used elsewhere in postgres CI). + curl.exe -fsSL -o openssl-setup.exe https://slproweb.com/download/Win64OpenSSL-1_1_1w.exe + Start-Process -Wait -FilePath ./openssl-setup.exe ` + -ArgumentList '/DIR=d:\openssl\1.1\ /VERYSILENT /SP- /SUPPRESSMSGBOXES' + # The slproweb installer puts libcrypto-1_1-x64.dll / libssl-1_1-x64.dll + # in d:\openssl\1.1\bin\ and updates the system PATH. GH Actions + # snapshots PATH at job start though, so the running job won't + # see those DLLs and initdb.exe would crash silently at runtime. + # Push the bin dir onto GITHUB_PATH so it persists for later steps. + Add-Content $env:GITHUB_PATH "d:\openssl\1.1\bin" + + # Install IPC::Run. + # - recommends_policy=0 keeps cpan from pulling in IO::Tty / IO::Pty, + # which don't build on Windows ("This module requires a POSIX + # compliant system to work"). + # - Pin to NJM/IPC-Run-20250809.0 because TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (changed pipe stdio + # handling). See upstream pg-vm-images commit ff5238afa3 and + # the thread at + # https://postgr.es/m/CAN55FZ06xanSbJdHe-CurjX_qNuBWZDEvS1kAk36L38YCtZXnw%40mail.gmail.com + "o conf recommends_policy 0`no conf commit`nnotest install NJM/IPC-Run-20250809.0.tar.gz" | cpan + perl -mIPC::Run -e 1 + + - name: Setup hosts file + shell: pwsh + run: | + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.1 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.2 pg-loadbalancetest" + Add-Content c:\Windows\System32\Drivers\etc\hosts "127.0.0.3 pg-loadbalancetest" + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Configure + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% %MESON_FEATURES% --buildtype debug -Db_pch=true -Dextra_lib_dirs=d:\openssl\1.1\lib -Dextra_include_dirs=d:\openssl\1.1\include -DTAR=%TAR% build + + - name: Build + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + ninja -C build %MBUILD_TARGET% + ninja -C build -t missingdeps + + - name: Test world + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + meson test %MTEST_ARGS% --num-processes %TEST_JOBS% + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-vs-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + + windows-mingw: + name: Windows - MinGW - Meson + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.mingw == 'true' && + needs.sanity-check.result != 'failure' + runs-on: windows-2022 + timeout-minutes: 60 + env: + TEST_JOBS: 4 # higher concurrency causes occasional failures + PG_TEST_USE_UNIX_SOCKETS: 1 + PG_REGRESS_SOCK_DIR: 'd:\pgsock' + TAR: "c:/windows/system32/tar.exe" + + MSYS: winjitdebug + CHERE_INVOKING: 1 + MSYSTEM: UCRT64 + + # Keep -Dnls explicitly disabled, as the number of files it creates + # causes a noticeable slowdown. + MESON_FEATURES: >- + -Dnls=disabled + + CCACHE_DIR: D:/a/ccache + CCACHE_MAXSIZE: "500M" + CCACHE_SLOPPINESS: pch_defines,time_macros + CCACHE_DEPEND: 1 + + defaults: + run: + shell: 'D:\msys64\usr\bin\bash.exe --login -eo pipefail "{0}"' + + steps: + - name: Disable Windows Defender + shell: powershell + run: | + Set-MpPreference -DisableRealtimeMonitoring $true -SubmitSamplesConsent NeverSend -MAPSReporting Disable + # Verify Defender status + $status = Get-MpComputerStatus -ErrorAction SilentlyContinue + if ($status) { + Write-Host "RealTimeProtectionEnabled: $($status.RealTimeProtectionEnabled)" + Write-Host "AntivirusEnabled: $($status.AntivirusEnabled)" + } + + - *checkout_step + + # Relocate the preinstalled MSYS2 tree from C:\ (slow system disk) to + # D:\ (faster ephemeral data disk). Every subsequent MSYS2 step uses + # D:\msys64\usr\bin\bash.exe via the job's `defaults.run.shell`. + # + # This reduces the total runtime of this task by ~15 minutes. + # + # robocopy returns 0-7 on success (with various "files copied" bits + # set) and 8+ on real failure, so we have to translate its exit code. + - name: Relocate MSYS2 to D + shell: powershell + run: | + robocopy C:\msys64 D:\msys64 /E /MT:16 /NJS /NJH /NFL /NDL /NP + if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } + exit 0 + + - name: Setup MSYS2 + run: | + # ${MINGW_PACKAGE_PREFIX} is an environment variable used in the + # MSYS2. It dynamically expands to the correct prefix for the active + # shell environment. + pacman -S --noconfirm --needed \ + git bison flex make diffutils \ + ${MINGW_PACKAGE_PREFIX}-ccache \ + ${MINGW_PACKAGE_PREFIX}-gcc \ + ${MINGW_PACKAGE_PREFIX}-icu \ + ${MINGW_PACKAGE_PREFIX}-libbacktrace \ + ${MINGW_PACKAGE_PREFIX}-libxml2 \ + ${MINGW_PACKAGE_PREFIX}-libxslt \ + ${MINGW_PACKAGE_PREFIX}-lz4 \ + ${MINGW_PACKAGE_PREFIX}-make \ + ${MINGW_PACKAGE_PREFIX}-meson \ + ${MINGW_PACKAGE_PREFIX}-perl \ + ${MINGW_PACKAGE_PREFIX}-pkg-config \ + ${MINGW_PACKAGE_PREFIX}-readline \ + ${MINGW_PACKAGE_PREFIX}-zlib + + - name: Install additional dependencies + run: | + # Pin IPC::Run to NJM/IPC-Run-20250809.0; TODDR/IPC-Run-20260322.0 + # broke postgres tap tests on Windows (pipe stdio handling). + # See pg-vm-images commit ff5238afa3. + (echo; echo o conf recommends_policy 0; echo notest install NJM/IPC-Run-20250809.0.tar.gz) | cpan + perl -mIPC::Run -e 1 + + - name: Setup socket directory + shell: cmd + run: mkdir %PG_REGRESS_SOCK_DIR% + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-mingw-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-mingw-${{ github.ref_name }}- + ccache-mingw- + + - name: Configure + run: | + meson setup \ + ${MESON_COMMON_PG_CONFIG_ARGS} \ + -Ddebug=true -Doptimization=g -Db_pch=true \ + ${MESON_COMMON_FEATURES} \ + ${MESON_FEATURES} \ + -DTAR=${TAR} \ + build + + - name: Build + run: ninja -C build ${MBUILD_TARGET} + + - name: Test world + run: meson test ${MTEST_ARGS} --num-processes ${TEST_JOBS} + + # FIX: We need to collect crashlogs but they are not collected. cdb.exe + # is installed on the runner so it needs to be configured. + - name: Upload logs + if: failure() + uses: actions/upload-artifact@v7 + with: + name: windows-mingw-logs-${{ github.run_id }} + path: *log_paths + if-no-files-found: ignore + + # Test that code can be built with both gcc and clang without warnings, + # with various combinations of cassert/dtrace flags. Trace probes have + # a history of getting accidentally broken; the matrix is there to + # catch that. + # + # The autoconf cache files (gcc.cache / clang.cache) are intentionally + # reused across the matrix entries that share a compiler, so we don't + # pay for full feature detection on every entry. + compiler-warnings: + name: CompilerWarnings + needs: [setup, sanity-check] + if: | + !cancelled() && + needs.setup.outputs.compilerwarnings == 'true' && + needs.sanity-check.result != 'failure' + runs-on: ubuntu-latest + timeout-minutes: 60 + container: + image: ${{ needs.setup.outputs.linux_ci_image }} + env: + BUILD_JOBS: 4 + CCACHE_DIR: /tmp/ccache_dir + # Use larger ccache cache as this job compiles with multiple + # compilers / flag combinations. + CCACHE_MAXSIZE: "1G" + steps: + - *checkout_step + + - name: Restore ccache + uses: actions/cache@v5 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-compiler-warnings-${{ github.ref_name }}-${{ github.run_id }} + restore-keys: | + ccache-compiler-warnings-${{ github.ref_name }}- + ccache-compiler-warnings- + + - name: Sysinfo + run: | + id + uname -a + cat /proc/cmdline + ulimit -a -H && ulimit -a -S + gcc -v + clang -v + env + + - name: Setup workspace + run: | + echo "COPT=-Werror" > src/Makefile.custom + mkdir -p "$CCACHE_DIR" + + # gcc, cassert off, dtrace on + - name: gcc warnings + (dtrace) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # gcc, cassert on, dtrace off + - name: gcc warnings + (cassert) + if: always() + run: | + ./configure \ + --cache gcc.cache \ + --enable-cassert \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert off, dtrace off + - name: clang warnings + if: always() + run: | + ./configure \ + --cache clang.cache \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + # clang, cassert on, dtrace on + - name: clang warnings + (cassert + dtrace) + if: always() + run: | + ./configure \ + --cache clang.cache \ + --enable-cassert \ + --enable-dtrace \ + ${LINUX_CONFIGURE_FEATURES} \ + CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + - name: mingw warnings (cross compilation) + if: always() + run: | + ./configure \ + --host=x86_64-w64-mingw32ucrt \ + --enable-cassert \ + --without-icu \ + CC="ccache x86_64-w64-mingw32ucrt-gcc" \ + CXX="ccache x86_64-w64-mingw32ucrt-g++" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} world-bin + + ### + # Verify docs can be built + ### + # XXX: Only do this if there have been changes in doc/ since last build + - name: Build documentation + if: always() + run: | + ./configure \ + --cache gcc.cache \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -C doc + + ### + # Verify headerscheck / cpluspluscheck succeed + # + # - Run both in same script to increase parallelism, use -k to get + # result of both + # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose + ### + - name: headerscheck + cpluspluscheck + if: always() + run: | + ./configure \ + ${LINUX_CONFIGURE_FEATURES} \ + --cache gcc.cache \ + --quiet \ + CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang" + make -s -j${BUILD_JOBS} clean + make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10' diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh index 63e97b37c78..18a06f96119 100755 --- a/src/tools/ci/ci_macports_packages.sh +++ b/src/tools/ci/ci_macports_packages.sh @@ -20,13 +20,26 @@ echo "macOS major version: $macos_major_version" # macOS release. macports_release_list_url="https://api.github.com/repos/macports/macports-base/releases"; macports_version_pattern="2\.10\.1" -macports_url="$( curl -s $macports_release_list_url | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" +# Authenticate the GitHub API request when a token is available (e.g. on +# GitHub Actions). Unauthenticated requests share a 60/h/IP rate limit +# with every other job on the runner's IP and frequently return an error +# JSON, leaving $macports_url empty and breaking the subsequent curl. +auth_header="" +if [ -n "$GITHUB_TOKEN" ]; then + auth_header="Authorization: Bearer $GITHUB_TOKEN" +fi +macports_url="$( curl -fsSL ${auth_header:+-H "$auth_header"} "$macports_release_list_url" | grep "\"https://github.com/macports/macports-base/releases/download/v$macports_version_pattern/MacPorts-$mac...-[A-Za-z]*\.pkg\"" | sed 's/.*: "//;s/".*//' | head -1 )" echo "MacPorts package URL: $macports_url" +if [ -z "$macports_url" ]; then + echo "error: could not determine MacPorts package URL for macOS $macos_major_version (version pattern: $macports_version_pattern)" 1>&2 + exit 1 +fi + cache_dmg="macports.hfs.dmg" -if [ "$CIRRUS_CI" != "true" ]; then - echo "expect to be called within cirrus-ci" 1>2 +if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then + echo "expect to be called within cirrus-ci or github actions" 1>2 exit 1 fi -- 2.54.0.380.gc69baaf57b --rv3g7aw7ud36z5b5 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6a-0002-gha-Andres-revisions.patch" ^ permalink raw reply [nested|flat] 153+ messages in thread
end of thread, other threads:[~2026-05-28 16:31 UTC | newest] Thread overview: 153+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2024-08-26 04:32 [PATCH v21 5/8] Row pattern recognition patch (executor). Tatsuo Ishii <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]> 2026-05-28 16:31 [PATCH v6a 1/5] Add GitHub Actions workflow for CI Nazir Bilal Yavuz <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox